package cz.ctu.guiproject.client;

import static cz.ctu.guiproject.client.resources.constants.Constants.CONNECTION_STATE;
import static cz.ctu.guiproject.client.resources.constants.Constants.CONNECT_LABEL;
import static cz.ctu.guiproject.client.resources.constants.Constants.DISCONNECT_LABEL;
import static cz.ctu.guiproject.client.resources.constants.Constants.UNSUPPORTED_CONNECTION_STATE;
import static cz.ctu.guiproject.client.resources.constants.Logger.TAG;
import android.app.Activity;
import android.app.Dialog;
import android.os.Bundle;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.EditText;
import android.widget.LinearLayout;
import cz.ctu.guiproject.client.dispatcher.Dispatcher;
import cz.ctu.guiproject.client.dispatcher.DispatcherImpl;
import cz.ctu.guiproject.client.dtos.State;
import cz.ctu.guiproject.client.formvalidation.EmptyStringValidator;
import cz.ctu.guiproject.client.formvalidation.Form;
import cz.ctu.guiproject.client.formvalidation.IpValidator;
import cz.ctu.guiproject.client.resources.ActivityProvider;
import cz.ctu.guiproject.client.resources.ContextProvider;
import cz.ctu.guiproject.client.resources.constants.Logger;
import cz.ctu.guiproject.client.resources.utils.ConfigProvider;

/**
 * 
 * @author tomas.buk
 */
public final class MainActivity extends Activity {

	private static final ContextProvider contextProvider;
	private static final ActivityProvider activityProvider;
	private static final Dispatcher dispatcher;
	private static Dialog dialog;
	private static State connectionState;

	static {
		connectionState = State.DISCONNECTED;
		contextProvider = ContextProvider.getInstance();
		activityProvider = ActivityProvider.getInstance();
		dispatcher = DispatcherImpl.getInstance();
	}

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		Log.i(Logger.TAG, "onCreate() called");
		// make Context and Activity available for all
		contextProvider.setContext(this);
		activityProvider.setActivity(this);
		handleSavedInstanceState(savedInstanceState);

		setContentView(R.layout.activity_main);

		// manually inflate dialog
		inflateDialog();
	}

	private void handleSavedInstanceState(Bundle savedInstanceState) {
		if (savedInstanceState != null) {
			final String connectionKey = savedInstanceState.getString(CONNECTION_STATE);
			if (connectionKey != null) {
				try {
					final State connectionState = State.valueOf(connectionKey);
					if (connectionState == State.CONNECTED) {
						dispatcher.setup();
						MainActivity.connectionState = connectionState;
					}
				} catch (IllegalArgumentException e) {
					Log.e(TAG, "Non-existing state: " + e.getMessage());
				}
			}
		}
	}

	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		// Inflate the menu; this adds items to the action bar if it is present.
		getMenuInflater().inflate(R.menu.main, menu);
		// according to connectionState set title on connectDisconnect menuItem
		final MenuItem item = menu.findItem(R.id.connectDisconnect);
		switch (connectionState) {
		case CONNECTED:
			item.setTitle(DISCONNECT_LABEL);
			break;
		case DISCONNECTED:
			item.setTitle(CONNECT_LABEL);
			break;
		default:
			throw new RuntimeException(UNSUPPORTED_CONNECTION_STATE);
		}
		return true;
	}

	@Override
	protected void onSaveInstanceState(Bundle outState) {
		super.onSaveInstanceState(outState);
		outState.putString(CONNECTION_STATE, connectionState.getValue());
	}

	private void inflateDialog() {
		final ConfigProvider configProvider = ConfigProvider.getInstance();
		
		dialog = new Dialog(this);
		dialog.setContentView(R.layout.prompt_dialog);
		dialog.setTitle("Server setup");

		// setup form validations
		final LinearLayout viewGroup = (LinearLayout) dialog.findViewById(R.id.dialog_layout);
		final Form<LinearLayout> form = new Form<LinearLayout>(viewGroup);

		// add IP address validator
		final EditText ipText = (EditText) dialog.findViewById(R.id.ip_value);
		ipText.setOnFocusChangeListener(new IpValidator(ipText));

		// add port number validator
		final EditText portText = (EditText) dialog.findViewById(R.id.port_value);
		portText.setOnFocusChangeListener(new EmptyStringValidator(portText));

		// add saved values to respective fields (if saved values exist)
		final String[] savedValues = configProvider.getConfig();
		ipText.setText(savedValues[0]);
		portText.setText(savedValues[1]);

		// handle required actions, before form is submitted
		final Button okButton = (Button) dialog.findViewById(R.id.btnSubmit);
		okButton.setOnClickListener(new OnClickListener() {

			@Override
			public void onClick(View v) {
				ipText.clearFocus();
				ipText.requestFocus();
				portText.clearFocus();
				portText.requestFocus();

				final EditText firstInvalid;
				if ((firstInvalid = form.isValid()) == null) {
					// save current values as default
					final String ipAddr = ipText.getText().toString();
					final String portNr = portText.getText().toString();
					configProvider.setConfig(new String[] { ipAddr, portNr });
					// close dialog
					dialog.dismiss();
				} else {
					// invalid input, request focus on first invalid form
					firstInvalid.requestFocus();
				}
			}
		});

		// cancel form
		final Button cancelButton = (Button) dialog.findViewById(R.id.btnCancel);
		cancelButton.setOnClickListener(new OnClickListener() {

			@Override
			public void onClick(View v) {
				// only close dialog
				dialog.dismiss();
			}
		});
	}

	@Override
	public boolean onOptionsItemSelected(MenuItem item) {
		// handle item selection
		switch (item.getItemId()) {
		case R.id.settings:
			dialog.show();
			break;
		case R.id.connectDisconnect:
			// make a connection / disconnect
			switch (connectionState) {
			case CONNECTED:
				connectionState = State.DISCONNECTED;
				item.setTitle(CONNECT_LABEL);
				dispatcher.disconnect();
				resetLayout();
				break;
			case DISCONNECTED:
				connectionState = State.CONNECTED;
				item.setTitle(DISCONNECT_LABEL);
				dispatcher.setup();
				break;
			default:
				throw new RuntimeException(UNSUPPORTED_CONNECTION_STATE);
			}
			break;
		}
		return super.onOptionsItemSelected(item);
	}

	private void resetLayout() {
		final ViewGroup parentContainer = (ViewGroup) findViewById(R.id.initialLayout);
		final int childViews = parentContainer.getChildCount();
		if (childViews > 0) {
			parentContainer.removeViews(0, childViews);
		}
	}
}
